using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace TXLooker.Hooks
{
    [Description("Component that hooks a window to the clipboard chain."), ToolboxBitmap(typeof(ClipboardHook), "clipboard.png"), DefaultEvent("StateChanged")]
    public class ClipboardHook : Component
    {
        private ClipboardPorc _clipboardProc;
        private IntPtr _nextWind;

        public event ClipboardEventHandler ClipboardChanged;

        public event StateEventHandler StateChanged;

        public ClipboardHook()
        {
            this._clipboardProc = new ClipboardPorc(this);
        }

        [DebuggerHidden]
        protected override void Dispose(bool disposing)
        {
            this.RemoveHook(false);
            base.Dispose(disposing);
        }

        [DebuggerHidden]
        public bool InstallHook(IntPtr hwnd, [Optional, DefaultParameterValue(true)] bool ThrowEx)
        {
            if (this.State == HookState.Uninstalled)
            {
                this._nextWind = Win32.SetClipboardViewer(hwnd);
                if (Marshal.GetLastWin32Error() != 0)
                {
                    this._nextWind = IntPtr.Zero;
                    if (ThrowEx)
                    {
                        throw new Win32Exception();
                    }
                    return false;
                }
                this._clipboardProc.AssignHandle(hwnd);
                this.OnStateChanged(new StateChangedEventArgs(this.State, this._clipboardProc.Handle));
                return true;
            }
            if (ThrowEx)
            {
                throw new InvalidOperationException("The object is already hooked.");
            }
            return false;
        }


        [DebuggerHidden]
        protected virtual void OnClipboardChanged(ClipboardEventArgs e)
        {
            ClipboardEventHandler clipboardChangedEvent = this.ClipboardChanged;
            if (clipboardChangedEvent != null)
            {
                clipboardChangedEvent(this, e);
            }
        }

        [DebuggerHidden]
        protected virtual void OnStateChanged(StateChangedEventArgs e)
        {
            StateEventHandler stateChangedEvent = this.StateChanged;
            if (stateChangedEvent != null)
            {
                stateChangedEvent(this, e);
            }
        }

        [DebuggerHidden]
        public bool RemoveHook([Optional, DefaultParameterValue(true)] bool ThrowEx)
        {
            if (this.State == HookState.Installed)
            {
                Win32.ChangeClipboardChain(this._clipboardProc.Handle, this._nextWind);
                if (Marshal.GetLastWin32Error() != 0)
                {
                    this._clipboardProc.ReleaseHandle();
                    this._nextWind = IntPtr.Zero;
                    if (ThrowEx)
                    {
                        throw new Win32Exception();
                    }
                    return false;
                }
                IntPtr handle = this._clipboardProc.Handle;
                this._clipboardProc.ReleaseHandle();
                this._nextWind = IntPtr.Zero;
                this.OnStateChanged(new StateChangedEventArgs(this.State, handle));
                return true;
            }
            if (ThrowEx)
            {
                throw new InvalidOperationException("The object is not hooked.");
            }
            return false;
        }

        public static System.Reflection.Assembly Assembly
        {
            [DebuggerHidden]
            get
            {
                return System.Reflection.Assembly.GetExecutingAssembly();
            }
        }

        public static string Author
        {
            [DebuggerHidden]
            get
            {
                return "Arman Ghazanchyan";
            }
        }

        [Browsable(false)]
        public IntPtr HWnd
        {
            [DebuggerHidden]
            get
            {
                return this._clipboardProc.Handle;
            }
        }

        [Browsable(false)]
        public HookState State
        {
            [DebuggerHidden]
            get
            {
                if (this._clipboardProc.Handle != IntPtr.Zero)
                {
                    return HookState.Installed;
                }
                return HookState.Uninstalled;
            }
        }

        public static System.Version Version
        {
            [DebuggerHidden]
            get
            {
                return Assembly.GetName().Version;
            }
        }

        public delegate void ClipboardEventHandler(object sender, ClipboardEventArgs e);

        private class ClipboardPorc : NativeWindow
        {
            private ClipboardHook _cHook;

            [DebuggerHidden]
            public ClipboardPorc(ClipboardHook cHook)
            {
                this._cHook = cHook;
            }

            [DebuggerHidden]
            protected override void WndProc(ref Message m)
            {
                if (m.Msg == 0x308)
                {
                    this._cHook.OnClipboardChanged(new ClipboardEventArgs(m.HWnd, m.WParam));
                    base.WndProc(ref m);
                }
                else if (m.Msg == 0x30d)
                {
                    if (m.WParam == this._cHook._nextWind)
                    {
                        this._cHook._nextWind = m.LParam;
                    }
                    else
                    {
                        base.WndProc(ref m);
                    }
                }
                else
                {
                    base.WndProc(ref m);
                }
            }
        }

        public delegate void StateEventHandler(object sender, StateChangedEventArgs e);
    }
}
